local U = require "packages/utility/utility"

local qin_generals = { "shangyang", "zhangyiq", "baiqi", "yingzheng", "lvbuwei", "zhaogao", "zhaoji", "miyue" } -- 秦将
local qin_soldiers = { "qin__qibing", "qin__bubing", "qin__nushou" } -- 秦兵
local han_generals = { "", "", "js__huangfusong", "js__zhujun", "js__duanwei", "os__luzhi", "", "" } -- 汉将

--- getSkills
---@param room Room
---@param num integer
---@return string[]
local function getSkills(room, num)
  num = num
  local skills = {}
  local skill_pool = room:getTag("skill_pool")
  if num > #skill_pool then return {} end
  for i = 1, num do
    local skill = table.random(skill_pool)
    table.removeOne(skill_pool, skill)
    table.insert(skills, skill)
  end
  return skills
end

local qinhan_getLogic = function()
  local qinhan_logic = GameLogic:subclass("qinhan_logic") ---@class GameLogic

  function qinhan_logic:initialize(room)
    GameLogic.initialize(self, room)
    self.role_table = { {"qin", "qin", "han", "han", "han", "han", "qin", "qin"} }
  end

  function qinhan_logic:assignRoles()
    local room = self.room
    local players = room.players
    local n = #players
    local roles = self.role_table[1]
    table.shuffle(players)
    for i = 1, n do
      local p = players[i]
      p.role = roles[i]
      p.role_shown = true
      room:broadcastProperty(p, "role")
    end
    self.start_role = players[1].role
    players[1].role = "lord"
  end

  function qinhan_logic:chooseGenerals()
    local room = self.room
    local generalNum = math.max(2, room.settings.generalNum)
    local n = room.settings.enableDeputy and 2 or 1
    local lord = room:getLord()
    room.current = lord
    lord.role = "qin"
    -- 选将
    table.shuffle(qin_generals)
    local ldgn = math.ceil(generalNum/4.5)
    local lords = { {}, {} }
    for x = 1, 2 do
      for y = 1, ldgn do
        table.insert(lords[x], qin_generals[(x-1)*ldgn+y])
      end
    end
    for i, p in ipairs(room.players) do
      local arg
      if table.contains({1,8}, i) then -- 秦将
        arg = lords[table.indexOf({1,8}, i)]
      elseif table.contains({2,7}, i) then -- 秦兵
        arg = qin_soldiers
      else -- 反贼
        local avatar = han_generals[i]
        room:setPlayerGeneral(p, avatar, false)
        p.kingdom = "han"
        room:notifyProperty(p, p, "kingdom")
        room:broadcastProperty(p, "general")
      end
      if arg then
        p.request_data = json.encode{ arg, n }
        p.default_reply = table.random(arg, n)
      end
    end
    -- 询问选将
    local to_ask = table.filter(room.players, function(p) return p.role == "qin" end)
    room:notifyMoveFocus(to_ask, "AskForGeneral")
    room:doBroadcastRequest("AskForGeneral", to_ask)
    -- 设置武将
    local selected = {}
    for _, p in ipairs(room.players) do
      if p.general == "" then
        if p.reply_ready then
          local general_ret = json.decode(p.client_reply)
          local general, deputy = general_ret[1], general_ret[2]
          table.insertTableIfNeed(selected, general_ret)
          room:setPlayerGeneral(p, general, true, true)
          room:setDeputyGeneral(p, deputy)
        else
          room:setPlayerGeneral(p, p.default_reply[1], true, true)
          room:setDeputyGeneral(p, p.default_reply[2])
          table.insertTableIfNeed(selected, p.default_reply)
        end
      end
      p.default_reply = ""
    end
  end
  
  function qinhan_logic:broadcastGeneral()
    local room = self.room
    local players = room.players

    for _, p in ipairs(players) do
      assert(p.general ~= "")
      local general = Fk.generals[p.general]
      local deputy = Fk.generals[p.deputyGeneral]
      p.maxHp = p:getGeneralMaxHp()
      p.hp = deputy and math.floor((deputy.hp + general.hp) / 2) or general.hp
      p.shield = math.min(general.shield + (deputy and deputy.shield or 0), 5)

      local changer = Fk.game_modes[room.settings.gameMode]:getAdjustedProperty(p)
      if changer then
        for key, value in pairs(changer) do
          p[key] = value
        end
      end
      local fixMaxHp = Fk.generals[p.general].fixMaxHp
      local deputyFix = Fk.generals[p.deputyGeneral] and Fk.generals[p.deputyGeneral].fixMaxHp
      if deputyFix then
        fixMaxHp = fixMaxHp and math.min(fixMaxHp, deputyFix) or deputyFix
      end
      if fixMaxHp then
        p.maxHp = fixMaxHp
      end
      p.hp = math.min(p.maxHp, p.hp)

      room:broadcastProperty(p, "general")
      room:broadcastProperty(p, "deputyGeneral")
      room:broadcastProperty(p, "kingdom")
      room:broadcastProperty(p, "maxHp")
      room:broadcastProperty(p, "hp")
      room:broadcastProperty(p, "shield")
    end
  end

  function qinhan_logic:attachSkillToPlayers()
    local room = self.room
    local n = room.settings.enableDeputy and 2 or 1
    local players = room.players
    -- 创建技能池
    local skill_pool = {}
    for _, g_name in ipairs(room.general_pile) do
      local general = Fk.generals[g_name]
      if general.kingdom ~= "qin" then
        local skillNameList = general:getSkillNameList()
        skillNameList = table.filter(skillNameList, function(s) return Fk.skills[s].frequency <= 3 end)
        table.insertTableIfNeed(skill_pool, skillNameList)
      end
    end
    room:setTag("skill_pool", skill_pool)
    -- 选3个技能
    local num = math.floor(1.5* room.settings.generalNum)
    local to_ask = table.filter(players, function (p)
      return p.role == "han"
    end)
    local toSelectSkills = getSkills(room, #to_ask*num)
    for i, p in ipairs(to_ask) do
      local choices = table.slice(toSelectSkills, (i-1)*num +1, i*num +1)
      p.request_data = json.encode({
        path = "packages/utility/qml/ChooseSkillBox.qml",
        data = {
          choices, 3*n, 3*n, "#kangqin-choose:::" .. tostring(3*n), {}
        },
      })
      p.default_reply = table.random(choices, 3*n)
    end
    room:doBroadcastRequest("CustomDialog", to_ask)
    for _, p in ipairs(to_ask) do
      local choice = p.reply_ready and json.decode(p.client_reply) or p.default_reply
      p.default_reply = ""
      room:handleAddLoseSkills(p, table.concat(choice, "|"), nil, false)
    end
    -- 上技能函数
    local addRoleModSkills = function(player, skillName)
      local skill = Fk.skills[skillName]
      if not skill then
        fk.qCritical("Skill: "..skillName.." doesn't exist!")
        return
      end
      if skill.lordSkill and (player.role ~= "lord" or #room.players < 5) then
        return
      end
      if #skill.attachedKingdom > 0 and not table.contains(skill.attachedKingdom, player.kingdom) then
        return
      end
      room:handleAddLoseSkills(player, skillName, nil, false)
    end
    -- 上技能
    local to_add = table.filter(players, function (p)
      return not table.contains(to_ask, p)
    end)
    for _, p in ipairs(to_add) do
      local skills = Fk.generals[p.general].skills
      for _, s in ipairs(skills) do
        addRoleModSkills(p, s.name)
      end
      for _, sname in ipairs(Fk.generals[p.general].other_skills) do
        addRoleModSkills(p, sname)
      end
      local deputy = Fk.generals[p.deputyGeneral]
      if deputy then
        skills = deputy.skills
        for _, s in ipairs(skills) do
          addRoleModSkills(p, s.name)
        end
        for _, sname in ipairs(deputy.other_skills) do
          addRoleModSkills(p, sname)
        end
      end
    end
  end

  return qinhan_logic
end

local qinhan_rule = fk.CreateTriggerSkill{
  name = "#qinhan_rule",
  priority = 0.001,
  mute = true,
  events = { fk.GameStart, fk.BuryVictim },
  can_trigger = function (self, event, target, player, data)
    return target == player
  end,
  on_cost = Util.TrueFunc,
  on_use = function(self, event, target, player, data)
    local room = player.room
    if event == fk.GameStart then
      room:setTag("SkipNormalDeathProcess", true)
      room:setTag("SkipGameRule", true)
      -- 事件
      local storys = {"#kq__bianfa", "#kq__lianheng", "#kq__changping", "#kq__hengsao", "#kq__chunqiu", "#kq__shaqiu", "#kq__zhaoji", "#kq__taihou"}
      local story = table.random(storys)
      room:setBanner("@[:]kq_story", story)
      room:handleAddLoseSkills(room.players[1], story, self.name, false, false)
    else
      for _, p in ipairs(room:getAlivePlayers()) do
        if p.kingdom ~= target.kingdom then
          room:drawCards(p, 1)
        end
      end
    end
  end,
}
Fk:addSkill(qinhan_rule)

local qinhan_mode = fk.CreateGameMode{
  name = "qinhan_mode",
  minPlayer = 8,
  maxPlayer = 8,
  logic = qinhan_getLogic,
  rule = qinhan_rule,
  winner_getter = function(self, victim)
    if not victim.surrendered and victim.rest > 0 then
      return ""
    end
    local room = victim.room
    local count = { qin = {}, han = {}}
    local alive = table.filter(room.alive_players, function(p)
      if not p.surrendered then
        table.insert(count[p.role], p.id)
      end
    end)
    if #count["qin"] > 0 then
      return #count["han"] > 0 and "" or "qin"
    else
      return "han"
    end
  end,
  surrender_func = function(self, playedTime)
    local room = Fk:currentRoom()
    local kingdomCheck = function ()
      for _, p in ipairs(room.alive_players) do
        if p ~= Self and p.role == self.role then
          return false
        end
      end
      return true
    end
    return { { text = "heg: besieged on all sides", passed = kingdomCheck } }
  end,
  get_adjusted = function (self, player)
    if player.role == "han" then
      return {hp = 4, maxHp = 4, kingdom = "han"}
    end
    return {}
  end
}

local qinhan_desc = [[
  
# 秦汉决战简介

  ---

  ## 身份说明

  游戏由8名玩家进行，8名玩家的身份分配如下：秦将，秦兵，汉将，汉将，汉将，汉将，秦兵，秦将

  ---

  ## 选将

  1. 秦将从8名秦势力武将中选择（嬴政、白起、芈月、赵姬、吕不韦、赵高、商鞅、张仪）

  2. 秦兵从3名秦势力武将中选择（步兵、骑兵、弩手）

  3. 汉将依次为（皇甫嵩、朱儁、段煨、卢植；均无技能），选将结束后从随机的一定数量（受房间选将数影响）的技能中选择3个获得

  ---

  ## 启用副将

  秦势力正常，为选择2名武将；汉势力则改为选择6个技能获得

  ---
  
  ## 随机事件

  1. **变法图强**：
  牌堆中加入3张【商鞅变法】；
  若场上有商鞅，则商鞅使用的【商鞅变法】的目标上限+1。
  
  2. **合纵连横**：
  每个回合开始时，所有角色横置；
  若场上有张仪，则拥有“横”标记的角色无法对横置状态的角色使用牌。
  
  3. **长平之战**：
  游戏开始时，进入鏖战状态（所有角色只能将【桃】当【杀】或【闪】使用、打出）；
  当一名角色成为【杀】的目标时，其需要额外使用一张【闪】抵消之；
  若场上有白起，则秦势力角色的回合开始时，其获得一张【桃】。

  4. **横扫六合**：
  牌堆中加入【传国玉玺】和【真龙长剑】；
  若场上有嬴政，游戏开始时，嬴政将【传国玉玺】和【真龙长剑】置入装备区。

  5. **吕氏春秋**：
  所有男性角色的额定摸牌数+1；
  若场上有吕不韦，当吕不韦摸牌时，摸牌数+1。

  6. **沙丘之变**：
  当一名角色死亡时，将其所有牌随机分配给所有男性角色；
  若场上有赵高，则将上述“随机分配给所有男性角色”改为“交给赵高”。

  7. **赵姬之乱**：
  当一名男性角色每回合首次造成伤害时，此伤害-1；
  若场上有赵姬，则将上述“男性角色”改为“非秦势力角色”。

  8. **始称太后**：
  游戏开始时，所有女性角色的体力值和体力上限+1；
  若场上有芈月，每名男性角色的回合开始时，其选择一项：1.令芈月回复1点体力；2.令芈月摸一张牌。

  ---

  ## 击杀奖惩

  一名角色死亡后，与其势力不同的角色各摸一张牌。

  ---

  <font color="gray">模式专属武将及模式专属卡牌请移步至OL扩展包查看</font>

]]

Fk:loadTranslationTable{
  ["qinhan_mode"] = "秦汉决战",
  [":qinhan_mode"] = qinhan_desc,
  ["#kangqin-choose"] = "从以下技能选择 %arg 个获得",
  ["@[:]kq_story"] = "事件",
}

local trans = {}
trans["han"] = "汉"

Fk:loadTranslationTable(trans)

return qinhan_mode